package com.kz.bot.task;

import com.kz.bot.config.TradeConfig;
import com.kz.bot.constant.OrderState;
import com.kz.bot.constant.Side;
import com.kz.bot.model.Order;
import com.kz.bot.model.OrderBook;
import com.kz.bot.model.TradeRecord;
import com.kz.bot.service.ApiService;
import com.kz.bot.util.MathCalculationUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class BotTask_first {

    private final TradeConfig config;
    private final ApiService apiService;

    @EventListener(ApplicationReadyEvent.class)
    public void onReady() {
        if (StringUtils.isBlank(config.getApiKey())
                || StringUtils.isBlank(config.getApiSecret())
                || StringUtils.isBlank(config.getApiPass())) {
            throw new RuntimeException("API Key, Secret, 或 Passphrase 未配置, 终止运行");
        }

        // --- 1. 初始化核心参数 ---
        OrderBook book = new OrderBook();
        String instId = config.getInstId();
        BigDecimal buyStep = config.getBuyStepLength();
        BigDecimal sellStep = config.getSellStepLength();
        int priceScale = config.getPriceScale();
        int volumeScale = config.getVolumeScale();
        BigDecimal tradeVolume = config.getTradeVolume();
        BigDecimal volumeMartin = config.getVolumeMartin();
        BigDecimal priceMartin = config.getPriceMartin();
        log.info("配置加载：Volume Martin = {}, Price Martin = {}", volumeMartin, priceMartin);


        // --- 2. 策略初始化：挂出或接管初始卖单 (基于您的原始逻辑) ---
        log.info("--- 策略初始化启动 ---");
        Order initialSellOrder;
        List<Order> currentSellOrders = apiService.currentOrder(instId, Side.sell);
        if (currentSellOrders.isEmpty()) {
            // 当前无卖单，需创建初始卖单
            log.info("未发现正在进行的卖单，开始创建初始卖单...");
            BigDecimal initialHoldVolume = apiService.queryAccountBalance(instId.replace("-USDT", ""));
            log.info("当前币种 {}, 持仓余额: {}", instId, initialHoldVolume);
            if (initialHoldVolume.compareTo(tradeVolume) < 0) {
                throw new RuntimeException(String.format("持仓不足，无法执行首次卖出。需要: %s, 实际: %s", tradeVolume, initialHoldVolume));
            }

            // 以当前最新价挂限价卖单，以确保快速成交
            BigDecimal sellPrice = apiService.queryLastPrice(instId);
            log.info("模拟市价卖出：以最新价 {} 挂出限价卖单", sellPrice);
            initialSellOrder = apiService.placeOrder(instId, Side.sell, tradeVolume, sellPrice);
            if (initialSellOrder == null) {
                throw new RuntimeException("启动时挂初始卖单失败");
            }
        } else {
            // 接管已存在的卖单
            if (currentSellOrders.size() > 1) {
                throw new RuntimeException("该账户下该币种当前存在的卖单超过1个，请处理后重启");
            }
            initialSellOrder = currentSellOrders.getFirst();
            log.info("发现并接管已存在的卖单，订单ID: {}", initialSellOrder.getOrdId());
        }

        // --- 3. 等待初始卖单成交 ---
        log.info("等待初始卖单 {} 成交...", initialSellOrder.getOrdId());
        while (true) {
            try {
                String status = apiService.queryOrderStatus(instId, initialSellOrder.getOrdId());
                if (OrderState.filled.name().equals(status)) {
                    log.info("初始卖单 {} 已成交！", initialSellOrder.getOrdId());
                    break; // 成交，跳出等待循环
                }
                if (OrderState.canceled.name().equals(status)) {
                    throw new RuntimeException("初始卖单 " + initialSellOrder.getOrdId() + " 已被取消，程序终止。");
                }
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("查询初始订单状态时出错，将重试...", e);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }

        // 使用Order对象中的价格作为成交价
        TradeRecord initialSellRecord = new TradeRecord();
        initialSellRecord.price = initialSellOrder.getPrice();
        initialSellRecord.volume = initialSellOrder.getVolume();
        book.sellHistory.add(initialSellRecord);
        log.info("首次真实卖出已记录！成交价: {}, 数量: {}", initialSellRecord.price, initialSellRecord.volume);


        // --- 4. 进入主策略循环 ---
        while (true) {
            try {
                // 4.1 每轮循环开始时，都根据当前状态计算并挂单
                recalculateAndPlaceOrders(book, instId, buyStep, sellStep, priceScale, volumeScale, tradeVolume, volumeMartin, priceMartin);

                // 4.2 进入状态监控，等待买单或卖单成交
                while (true) {
                    String buyOrderStatus = apiService.queryOrderStatus(instId, book.currentBuyOrder.getOrdId());
                    if (OrderState.filled.name().equals(buyOrderStatus)) {
                        log.info("--- 周期结束：买单已成交! ---");
                        log.info("成交详情 - 价格: {}, 数量: {}", book.currentBuyOrder.getPrice(), book.currentBuyOrder.getVolume());

                        apiService.cancelOrder(instId, book.currentSellOrder.getOrdId());
                        log.info("已取消对应的卖单: {}", book.currentSellOrder.getOrdId());

                        // 开启新周期 (虚拟卖出)
                        BigDecimal newCycleVirtualPrice = book.currentBuyOrder.getPrice(); // 使用买单对象中的价格
                        log.info("--- 新交易周期启动 (虚拟卖出), 基准价: {} ---", newCycleVirtualPrice);

                        book.sellHistory.clear();
                        TradeRecord virtualSell = new TradeRecord();
                        virtualSell.price = newCycleVirtualPrice;
                        virtualSell.volume = tradeVolume;
                        book.sellHistory.add(virtualSell);

                        break; // 跳出内层监控循环，回到外层重新计算挂单
                    }

                    String sellOrderStatus = apiService.queryOrderStatus(instId, book.currentSellOrder.getOrdId());
                    if (OrderState.filled.name().equals(sellOrderStatus)) {
                        log.info("--- 档位上升：卖单已成交! ---");
                        log.info("成交详情 - 价格: {}, 数量: {}", book.currentSellOrder.getPrice(), book.currentSellOrder.getVolume());

                        TradeRecord filledSell = new TradeRecord();
                        filledSell.price = book.currentSellOrder.getPrice(); // 使用卖单对象中的价格
                        filledSell.volume = book.currentSellOrder.getVolume();
                        book.sellHistory.add(filledSell);

                        apiService.cancelOrder(instId, book.currentBuyOrder.getOrdId());
                        log.info("已取消对应的买单: {}", book.currentBuyOrder.getOrdId());

                        break; // 跳出内层监控循环，回到外层重新计算挂单
                    }

                    Thread.sleep(3000);
                }

            } catch (InterruptedException e) {
                log.error("线程被中断", e);
                Thread.currentThread().interrupt();
                break;
            } catch (Exception e) {
                log.error("主循环中发生未知异常, 需要排查日志", e);
                break;
            }
        }
    }

    /**
     * 核心函数：根据当前的交易历史，计算并挂出新的一对买卖订单
     */
    private void recalculateAndPlaceOrders(OrderBook book, String instId, BigDecimal buyStep, BigDecimal sellStep, int priceScale, int volumeScale, BigDecimal initialTradeVolume, BigDecimal volumeMartin, BigDecimal priceMartin) {
        // ... (前面的计算逻辑都不变)
        BigDecimal totalSellVolume = BigDecimal.ZERO;
        BigDecimal weightedSum = BigDecimal.ZERO;
        for (TradeRecord t : book.sellHistory) {
            weightedSum = weightedSum.add(t.getPrice().multiply(t.getVolume()));
            totalSellVolume = totalSellVolume.add(t.getVolume());
        }
        BigDecimal avgSellPrice = weightedSum.divide(totalSellVolume, priceScale, RoundingMode.HALF_UP);
        log.info("当前累计卖出 {} 档, 总卖出量: {}, 平均卖价: {}", book.sellHistory.size(), totalSellVolume, avgSellPrice);

        BigDecimal targetBuyPrice = avgSellPrice.multiply(BigDecimal.ONE.subtract(buyStep)).setScale(priceScale, RoundingMode.HALF_UP);

        BigDecimal currentUsdtBalance = apiService.queryAccountBalance("USDT");
        BigDecimal reservedPrincipal = initialTradeVolume.multiply(targetBuyPrice);

        // 【核心修正】
        // 1. 计算所有可用于回购的USDT（利润 + 额外卖出的本金）
        BigDecimal spendableUsdt = currentUsdtBalance.subtract(reservedPrincipal);

        // 2. 直接用可支配的USDT计算总买入量
        BigDecimal totalBuyVolume;
        if (spendableUsdt.compareTo(BigDecimal.ZERO) > 0) {
            totalBuyVolume = spendableUsdt.divide(targetBuyPrice, volumeScale, RoundingMode.DOWN);
        } else {
            // 这是一个保护性分支，正常情况下不应该进入
            log.error("计算出的可支配USDT小于等于0，无法挂买单。USDT余额: {}, 预留本金: {}", currentUsdtBalance, reservedPrincipal);
            throw new RuntimeException("计算出的总买入量异常，程序终止。");
        }

        // 【删除错误逻辑】
        // BigDecimal buyVolumeForProfit = ...
        // BigDecimal additionalSoldVolume = ...
        // BigDecimal totalBuyVolume = buyVolumeForProfit.add(additionalSoldVolume); // <-- 这行是错误的，已删除

        if (totalBuyVolume.compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException("计算出的总买入量小于等于0，程序异常终止。请检查账户余额和配置。");
        }

        book.currentBuyOrder = apiService.placeOrder(instId, Side.buy, totalBuyVolume, targetBuyPrice);
        if (book.currentBuyOrder == null) throw new RuntimeException("挂买单失败!");
        log.info("挂出新的聚合买单，价格: {}, 数量: {}", targetBuyPrice, totalBuyVolume);

        // ====== 下一档位卖价计算公式1 ======
        // 下一档价格 = 上一档价格 * (1 + 基础步长 * (马丁系数 ^ N))
        // ... (后续挂卖单的逻辑不变)
        BigDecimal dynamicPriceStep = sellStep.multiply(
                MathCalculationUtil.pow(priceMartin, BigDecimal.valueOf(book.sellHistory.size()), 10)
        );

        // 方案1 使用平均卖价计算下一档位的卖价
//        BigDecimal nextSellPrice = avgSellPrice.multiply(BigDecimal.ONE.add(dynamicPriceStep)).setScale(priceScale, RoundingMode.HALF_UP);
        // 方案2 使用上一次卖价计算下一档位卖价
        BigDecimal preSellOrderPrice = book.getSellHistory().getLast().price;
        BigDecimal nextSellPrice = preSellOrderPrice.multiply(BigDecimal.ONE.add(dynamicPriceStep)).setScale(priceScale, RoundingMode.HALF_UP);

        /*// ====== 下一档位卖价计算公式2 ======
        // 下一档价格 = (上一档价格 * (1 + 基础步长)) * (马丁系数 ^ N)
        BigDecimal priceMartinMultiplier = MathCalculationUtil.pow(priceMartin, BigDecimal.valueOf(book.sellHistory.size()), 10);
        BigDecimal nextSellPrice = preSellOrderPrice.multiply(BigDecimal.ONE.add(sellStep)).multiply(priceMartinMultiplier);
        // ====== 下一档位卖价计算公式2 ======*/

        BigDecimal nextMartinVolume = initialTradeVolume.multiply(
                MathCalculationUtil.pow(volumeMartin, BigDecimal.valueOf(book.sellHistory.size()), 10)
        ).setScale(volumeScale, RoundingMode.DOWN);

        book.currentSellOrder = apiService.placeOrder(instId, Side.sell, nextMartinVolume, nextSellPrice);
        if (book.currentSellOrder == null) throw new RuntimeException("挂卖单失败!");
        log.info("挂出更高价位的新卖单，价格: {} (动态间距: {}%), 数量: {}", nextSellPrice, dynamicPriceStep.multiply(BigDecimal.valueOf(100)).setScale(4, RoundingMode.HALF_UP), nextMartinVolume);
    }
}